Witai Agent

Rishabh Jain 9 lat temu
rodzic
commit
e4652e2d8d

+ 77 - 0
app/models/agents/witai_agent.rb

@@ -0,0 +1,77 @@
1
+module Agents
2
+  class WitaiAgent < Agent
3
+    cannot_be_scheduled!
4
+
5
+    description <<-MD
6
+
7
+    `wit.ai` agent receives events, sends text query to your `wit.ai` instance and generates outcome events. Fill in `Server Access Token` of your `wit.ai` instance. Use [Liquid](https://github.com/cantino/huginn/wiki/Formatting-Events-using-Liquid) to fill query field.
8
+    `expected_receive_period_in_days` is the expected number of days by which agent should receive events. It helps in determining if the agent is working.
9
+    MD
10
+
11
+    event_description <<-MD
12
+
13
+    Every event have `outcomes` key with your payload as value. Sample event:
14
+
15
+        {"outcome" : [
16
+          {"_text" : "set temperature to 34 degrees at 11 PM",
17
+           "intent" : "get_temperature",
18
+           "entities" : {
19
+             "temperature" : [
20
+             {
21
+               "type" : "value",
22
+               "value" : 34,
23
+               "unit" : "degree"
24
+             }],
25
+             "datetime" : [
26
+             {
27
+               "grain" : "hour",
28
+               "type" : "value",
29
+               "value" : "2015-03-26T21:00:00.000-07:00"
30
+             }]},
31
+             "confidence" : 0.556
32
+           }]}
33
+    MD
34
+
35
+    def default_options
36
+      {
37
+       'server_access_token' => 'xxxxx',
38
+       'expected_receive_period_in_days' => 2,
39
+       'query' => '{{xxxx}}'
40
+      }
41
+    end
42
+
43
+    def working?
44
+      !recent_error_logs? && most_recent_event && event_created_within?(interpolated['expected_receive_period_in_days'])
45
+    end
46
+
47
+    def validate_options
48
+      unless %w[server_access_token query expected_receive_period_in_days].all? { |field| options[field].present? }
49
+        errors.add(:base, 'All fields are required')
50
+      end
51
+    end
52
+
53
+    def receive(incoming_events)
54
+      incoming_events.each do |event|
55
+        interpolated_event = interpolated event
56
+        response = HTTParty.get query_url(interpolated_event[:query]), headers
57
+        create_event 'payload' => {
58
+          'outcomes' => JSON.parse(response.body)['outcomes']
59
+        }
60
+      end
61
+    end
62
+
63
+    private
64
+      def api_endpoint
65
+        'https://api.wit.ai/message?v=20141022&q='
66
+      end
67
+
68
+      def query_url(query)
69
+        api_endpoint + URI.encode(query)
70
+      end
71
+
72
+      def headers
73
+        #oauth
74
+        {:headers => {'Authorization' => 'Bearer ' + interpolated[:server_access_token]}}
75
+      end
76
+  end
77
+end

+ 27 - 0
spec/data_fixtures/witai.json

@@ -0,0 +1,27 @@
1
+{
2
+  "msg_id":"x",
3
+  "_text":"x",
4
+  "outcomes": [
5
+    {
6
+      "_text": "set the temperature to 22 degrees at 7 PM",
7
+      "intent": "get_temparature",
8
+      "entities": {
9
+        "datetime": [
10
+          {
11
+            "grain": "hour",
12
+            "type": "value",
13
+            "value": "2015-03-27T21:00:00.000-07:00"
14
+          }
15
+        ],
16
+        "temperature": [
17
+          {
18
+            "type": "value",
19
+            "value": 34,
20
+            "unit": "degree"
21
+          }
22
+        ]
23
+      },
24
+      "confidence": 0.554
25
+    }
26
+  ]
27
+}

+ 71 - 0
spec/models/agents/witai_agent_spec.rb

@@ -0,0 +1,71 @@
1
+require 'spec_helper'
2
+
3
+describe Agents::WitaiAgent do
4
+  before do
5
+    stub_request(:get, /wit/).to_return(:body => File.read(Rails.root.join('spec/data_fixtures/witai.json')), :status => 200, :headers => {'Content-Type' => 'text/json'})
6
+
7
+    @valid_params = {
8
+      :server_access_token => 'x',
9
+      :expected_receive_period_in_days => '2',
10
+      :query => '{{message.content}}'
11
+    }
12
+
13
+    @checker = Agents::WitaiAgent.new :name => 'wit.ai agent',
14
+                                      :options => @valid_params
15
+
16
+    @checker.user = users :jane
17
+    @checker.save!
18
+
19
+    @event = Event.new
20
+    @event.agent = agents :jane_weather_agent
21
+    @event.payload = {:message => {
22
+      :content => 'set the temperature to 22 degrees at 7 PM'
23
+    }}
24
+    @event.save!
25
+  end
26
+
27
+  describe '#validation' do
28
+    before do
29
+      expect(@checker).to be_valid
30
+    end
31
+
32
+    it 'validates presence of server access token' do
33
+      @checker.options[:server_access_token] = nil
34
+      expect(@checker).not_to be_valid
35
+    end
36
+
37
+    it 'validates presence of query' do
38
+      @checker.options[:query] = nil
39
+      expect(@checker).not_to be_valid
40
+    end
41
+
42
+    it 'validates presence of expected receive period in days key' do
43
+      @checker.options[:expected_receive_period_in_days] = nil
44
+      expect(@checker).not_to be_valid
45
+    end
46
+  end
47
+
48
+  describe '#working' do
49
+    it 'checks if agent is working when event is received withing expected number of days' do
50
+      expect(@checker).not_to be_working
51
+      Agents::WitaiAgent.async_receive @checker.id, [@event.id]
52
+      expect(@checker.reload).to be_working
53
+      two_days_from_now = 2.days.from_now
54
+      stub(Time).now { two_days_from_now }
55
+      expect(@checker.reload).not_to be_working
56
+    end
57
+  end
58
+
59
+  describe '#receive' do
60
+    it 'checks that a new event is created after receiving one' do
61
+      expect {
62
+        @checker.receive([@event])
63
+      }.to change { Event.count }.by(1)
64
+    end
65
+
66
+    it 'checks the integrity of new event' do
67
+      @checker.receive([@event])
68
+      expect(Event.last.payload[:outcomes][0][:_text]).to eq(@event.payload[:message][:content])
69
+    end
70
+  end
71
+end